comment ^
        Comments are in serbian, because I feel more confortable writing in
        my native language... 
        This is brain of engine and has a few procedures (check import.txt)
        
        NOTE !!!!!
        due to my tasm32 inc files here is present pinfo.pi_hProcess which is
        PROCESS_INFORMATION.hProcess...
        So just define some struct with member pi_hProcess and store there 
        process handle of your target... or use my struct:
        
        process_information     struct
                pi_hProcess     dd      ?
                pi_hThread      dd      ?
                pi_dwProcessId  dd      ?
                pi_dwThreadId   dd      ?
        process_information     ends
        
        Also if you want you may write other kinds of locate_api/locate_dll
        just note that engine assumes that is_apiname has API name or ordinal | MSB
        and also is_apilen and is_dlllen are also required for engine to work properly...
        
        For example you can run nointrusive tracer on some pointer and then use your
        own locate_api/locate_dll to get valid api pointer, but this is only designed
        as helper tool once I get working dump with apiloader.
        
                                        S verom u Boga, deroko/ARTeam
        
^
                       
modules                 dd      1024    dup(0)                       
peheaderXxX             db      1024     dup(0)
dummyXxX                dd      ?
dllname                 db      1024     dup(0)
sysdir                  db      1024     dup(0)
syslen                  dd      ?


import_struct           struct
        is_address      dd      ?
        is_dlllen       dd      ?
        is_apilen       dd      ?
        is_dllname      db      256     dup(0)
        is_apiname      db      256     dup(0)  ;might be ordinal aswell...
import_struct           ends


;unutra:  eax - pointer ka import_struct
;napolje: eax - velicina nove sekcije, ecx broj image_import_descriptora 
get_imp_size:           pusha
                        mov     ebx, [esp+24h]
                        xor     ecx, ecx
                        xor     eax, eax                        ;
                        
__cycle_size:           add     ecx, size import_directory      ;veliina image_import_descriptora
                        inc     eax      
                        add     ecx, [ebx.is_dlllen]            ;velcina dll-a
                        add     ecx, [ebx.is_apilen]            ;velicina APIja
                        add     ecx, 2                          ;za hint
                        add     ecx, 10h                        ;+8 za [RVA][0] za original first thunk... i +8 tj. tri na karte
                        add     ebx, size import_struct
                        cmp     [ebx.is_address], 0
                        jne     __cycle_size
                        
                        add     ecx, size import_directory      ;+1 image_import_descriptor za terminiranje importa
                        inc     eax

                        mov     [esp.Pushad_eax], ecx
                        mov     [esp.Pushad_ecx], eax
                        popa
                        retn    4
                        
;samo vraca adresu ka systemskom direktorijumu...
get_system_dir:         pusha
                        call    GetSystemDirectoryA, o sysdir, 256
                        mov     syslen, eax
                        popa
                        retn

;u eax adresa apija natrag string ka dllu...
locate_dll:             pusha
                        mov     esi, eax
                        call    EnumProcessModules, pinfo.pi_hProcess, o modules, 1000h, o dummyXxX

                        xor     ebx, ebx
                        dec     ebx
                        
__cycle_modules:        inc     ebx
                        call    ReadProcessMemory, pinfo.pi_hProcess, modules[ebx*4], o peheaderXxX, 1024, 0
                        mov     eax, offset peheaderXxX
                        add     eax, [eax+3ch]
                        mov     eax, [eax.pe_sizeofimage]
                        add     eax, modules[ebx*4]
                        
                        cmp     esi, modules[ebx*4]
                        jb      __cycle_modules
                        cmp     esi, eax
                        jnb     __cycle_modules
                        
                        call    GetModuleFileNameExA, pinfo.pi_hProcess, modules[ebx*4], o dllname, 1024
                        mov     edx, modules[ebx*4]
                        xchg    eax, ebx
                        mov     esi, offset dllname
                        mov     edi, offset sysdir
                        mov     ecx, syslen
                        cld
                        rep     cmpsb  
                        mov     eax, offset dllname                   
                        jnz     __not_same
                        inc     esi
                        mov     eax, esi                        
__not_same:             mov     [esp.Pushad_ecx], edx           ;address of dll in target process...
                        mov     [esp.Pushad_eax], eax
                        popa
                        retn
                        
;u eax api, vani ime apija ili ordinal + MSB
locate_api:             pusha
                        mov     esi, eax
                        call    locate_dll
                        sub     esi, ecx
                        call    LoadLibraryA, eax
                        mov     ebx, eax
                        add     esi, eax
                        
                        add     ebx, [ebx+3ch]
                        
                        mov     edi, [ebx.pe_export]
                        add     edi, eax
                        mov     ebx, eax
                        
                        mov     ecx, [edi.ed_addressoffunctions]
                        add     ecx, ebx
                        

                        xor     eax, eax
                                                
__cycle_ordinals:       mov     edx, dword ptr[ecx+eax*4]
                        add     edx, ebx
                        
                        cmp     edx, esi
                        je      __locate_api_name1
                        inc     eax
                        cmp     eax, [edi.ed_numberoffunctions]
                        jb      __cycle_ordinals

;licraj ime APIja ili ordinal ako ima neki
__locate_api_name1:
                        mov     esi, [edi.ed_addressofordinals]
                        add     esi, ebx
                        sub     esi, 2
                        xor     ecx, ecx
                        dec     ecx
                                                
__locate_api_name:      add     esi, 2
                        inc     ecx
                        cmp     word ptr[esi], ax
                        je      __check_for_name
                        cmp     ecx, [edi.ed_numberoffunctions]
                        jb      __locate_api_name
                        
__check_for_name:       cmp     ecx, [edi.ed_numberofnames]
                        ja      __ordinal
                        
                        mov     esi, [edi.ed_addressofnames]
                        add     esi, ebx
                        mov     eax, [esi+ecx*4]
                        add     eax, ebx
                        jmp     __e_l_api

__ordinal:              add     eax, [edi.ed_base]
                        or      eax, 80000000h

__e_l_api:              mov     [esp.Pushad_eax], eax
                        popa
                        retn 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;mozak engina koji pravi virtuelni IAT relativan sa alociranim bufferom
;
;argumenti:
;1. RVA nove sekcije
;2. pointer na import_strukture
;3. velicina IATa (dobija se zbirom svih entryija u import_strukturi)
;4. koliko ima import descriptora... (ukupan broj import deskriptora + 1 za null)
;vraca:
; eax = pointer na novi IAT koji se moze slobodno prekopirati kao nova sekcija... 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;                                                
build_import_table      proc
                        arg     iat_sec_rva:dword
                        arg     is_mem_ptr:dword
                        arg     iat_size:dword
                        arg     id_num:dword
                        local   new_iat_mem:dword
                        pusha
                        
                        call    VirtualAlloc, 0, iat_size, MEM_COMMIT, PAGE_READWRITE
                        mov     new_iat_mem, eax

;organizacija           -       edx pokazuje na import_struckture
;                       -       ebx pokazuje na image_import_descriptor
;                       -       eax pokazuje na mesta gde pisemo adrese nasih importa (original_first_thunk)
;                       -       edi pokazuje na prostor iza mesta rezervisanog za original_first_thunk

                        mov     edx, is_mem_ptr
                        mov     ebx, eax                ;memorija alocirana sa VirtualAlloc
                        mov     eax, id_num
                        imul    eax, eax, size import_directory
                        add     eax, new_iat_mem
                        mov     edi, id_num
                        imul    edi, edi, 8
                        add     edi, eax

                        
;i krecemo da vrtimo dok se ovo ne zavrsi sve...
                        sub     edx, size import_struct
                        
__cycle_main_loop:      add     edx, size import_struct
                        cmp     [edx.is_address], 0
                        je      __done_building
                
                        ;kopiramo .dll...
                        mov     esi, edi
                        sub     esi, new_iat_mem
                        add     esi, iat_sec_rva
                        
                        mov     [ebx.id_name], esi 
                        lea     esi, [edx.is_dllname]
                        mov     ecx, [edx.is_dlllen]
                        rep     movsb
                        
                        ;sad upisujemo originalfirstthunk i firstthunk...
                        mov     esi, eax
                        sub     esi, new_iat_mem
                        add     esi, iat_sec_rva
                        
                        mov     [ebx.id_originalfirstthunk], esi
                        
                        mov     esi, dword ptr[edx.is_apiname]
                        test    esi, 80000000h
                        jz      __api_has_name
                        mov     [eax], esi
                        jmp     __firstthunk         

__api_has_name:
                        mov     esi, edi
                        sub     esi, new_iat_mem
                        add     esi, iat_sec_rva
                        mov     [eax], esi
             
                        lea     esi, [edx.is_apiname]
                        add     edi, 2
                        mov     ecx, [edx.is_apilen]
                        rep     movsb

__firstthunk:                        
                        mov     esi, [edx.is_address]
                        mov     [ebx.id_firstthunk], esi
                        
                        add     ebx, size import_directory
                        add     eax, 8
                        jmp     __cycle_main_loop
                        
                                        
                        

                        
__done_building:        mov     eax, new_iat_mem
                        mov     [esp.Pushad_eax], eax
                        popa
                        leave
                        retn    10h
                        endp
                        


;unutra eax ka mapiranom fajlu... sad namestamo da firstthunk pokazuje na ono nasta pokazuje
;i originalfirstthunk, trik je ovde da NT loader na winXP proverava prov OriginalFirstThunk,
;ako je on 0 onda proverava FirstThunk za importima, ali iz nekog razloga u LdrpHandleOneOldFormatImportDescriptor
;proverava da li je FirstThunk 0 ali sve podatke vadi iz originalfirst thunk... cudno... hmmmm ko ce ga znade :P     
adjust_first_thunk:     pusha
                        mov     esi, eax
                        mov     ebx, [eax+3ch]
                        add     ebx, esi
                        
                        mov     edi, [ebx.pe_import]
                        call    find_raw, esi, edi
                        xchg    eax, edi
                        add     edi, esi                
                        
__cycle_adjust:         cmp     [edi.id_name], 0
                        je      __adjust_ok
            
                        mov     eax, [edi.id_originalfirstthunk]
                        call    find_raw, esi, eax
                        add     eax, esi
                        
                        mov     ecx, [eax]              ;grab address from first thunk
                        
                        mov     eax, [edi.id_firstthunk]
                        call    find_raw, esi, eax
                        add     eax, esi
                        
                        mov     [eax], ecx
                        
                        add     edi, size import_directory
                        jmp     __cycle_adjust            
                        
__adjust_ok:            popa
                        retn
                        
find_raw                proc
                        arg     mapped_file:dword
                        arg     rva:dword
                        pusha
                        mov     esi, rva
                        mov     ebx, mapped_file
                        add     ebx, [ebx+3ch]
                        lea     eax, [ebx+0f8h]
                        sub     eax, size image_section_header
                        
__cycle_sectionXxX:     add     eax, size image_section_header
                        mov     edx, [eax.sh_virtualaddress]
                        cmp     esi, edx
                        jb      __cycle_sectionXxX
                        add     edx, [eax.sh_virtualsize]
                        cmp     esi, edx
                        jnb     __cycle_sectionXxX
                        
                        sub     esi, [eax.sh_virtualaddress]
                        add     esi, [eax.sh_pointertorawdata]
                        
                        mov     [esp.Pushad_eax], esi
                        popa
                        leave
                        retn    8
                        endp


;handle forwards cini importe win2k/98 compatibilnim
;prototip : handle_forwards     proc
;                               arg     import_structs_pointer:dword
;pri cemu je import_structs_pointer pointer ka vec popunjenim import_struct
;kako radi?
;       1. proverava da li je API iz ntdll.dll
;       2. ako je ntdll.dll, onda trazimo da li je takav API forwardovan u kernel32
;          koristeci se logikom NTDLL.API_Name
;       3. ako je tako, umesto ntdll.dll ubacujemo kernel32.dll i API koji je 
;          exportovan iz kernel32.dll
;
XxXkernel32             db      "kernel32.dll", 0
XxXntdll                db      "ntdll.dll", 0
handle_forwards:        pusha
                        
                        mov     ebx, [esp+24h]
                        sub     ebx, size import_struct

__cycle_forwards:       add     ebx, size import_struct
                        cmp     [ebx.is_address], 0
                        je      __e_forwards
                        
                        lea     esi, [ebx.is_dllname]
                        call    lstrcmpiA, esi, o XxXntdll
                        test    eax, eax
                        jnz     __cycle_forwards

;ovde sad imamo API iz ntdll.dll sad moramo proceljati kernel32.dll za 
;forward APIjima i porediti stringove, ako nadjemo pravi API onda cemo
;prosto zameniti imena dll-a i APIja i to je to...
                        lea     esi, [ebx.is_apiname]
                        call    cycle_k32_f, esi
                        jb      __cycle_forwards
                        
;kopiramo ime APIja is_apiname i postavljamo is_dllname na kernel32.dll
;takodje ujedno ubacujemo duzine apija i dlla u is_apilen i is_dlllen
                        mov     esi, eax
                        lea     edi, [ebx.is_apiname]
                        call    copy_strXxX
                        mov     [ebx.is_apilen], ecx
                        
                        mov     esi, offset XxXkernel32
                        lea     edi, [ebx.is_dllname]
                        call    copy_strXxX
                        mov     [ebx.is_dlllen], ecx
                        jmp     __cycle_forwards
                        
__e_forwards:           popa
                        retn    4
                        endp


copy_strXxX:            push    eax
                        xor     ecx, ecx
__csXxX:                lodsb
                        stosb
                        inc     ecx
                        test    al, al
                        jnz     __csXxX
                        pop     eax
                        retn
                        
cycle_k32_f             proc
                        arg     f_string:dword
                        local   k32dllbase:dword
                        local   number_of_names:dword
                        pusha
                        
                        call    LoadLibraryA, o XxXkernel32
                        mov     k32dllbase, eax
                        xchg    eax, ebx
                        
                        add     ebx, [ebx+3ch]
                        
                        mov     ebx, [ebx.pe_export]
                        add     ebx, k32dllbase
                        
                        mov     eax, [ebx.ed_numberofnames]
                        mov     number_of_names, eax
                        
                        xor     esi, esi
                        
                        mov     edi, [ebx.ed_addressofordinals]
                        add     edi, k32dllbase
                                              
__cycle_names_f:        movzx   edx, word ptr[edi+esi*2]
                        mov     eax, [ebx.ed_addressoffunctions]
                        add     eax, k32dllbase
                        mov     eax, [eax+edx*4]
                        add     eax, k32dllbase
                        add     eax, 6
                        
                        call    lstrcmp, eax, f_string
                        test    eax, eax
                        jz      __found_forward
                        inc     esi
                        cmp     esi, number_of_names
                        jb      __cycle_names_f
                        stc
                        jmp     __e_ckf
__found_forward:        mov     eax, [ebx.ed_addressofnames]
                        add     eax, k32dllbase
                        mov     eax, [eax+esi*4]
                        add     eax, k32dllbase
                        clc                        
__e_ckf:                mov     [esp.Pushad_eax], eax
                        popa
                        leave
                        retn    4
                        endp                                                           